entry completion: Use a popover
authorMatthias Clasen <mclasen@redhat.com>
Sat, 20 Apr 2019 04:32:29 +0000 (04:32 +0000)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 28 May 2019 20:25:13 +0000 (20:25 +0000)
This lets us remove a use of GTK_WINDOW_POPUP,
which should eventually be going away.

We need to disable treeview search, since it
creates a toplevel that will disrupt our grabbing
popup, causing it to be dismissed.

We don't need to grab ourselves, since the popover
code does it for us. We don't need to reposition our
window, since the popover takes care of that too.

gtk/gtkentrycompletion.c

index fb6cb1709f45a8016d4b3877b569d31a09863420..068a6b271ca4d751be70905a341febc844aa084d 100644 (file)
@@ -79,8 +79,7 @@
 #include "gtkscrolledwindow.h"
 #include "gtksizerequest.h"
 #include "gtkbox.h"
-#include "gtkwindow.h"
-#include "gtkwindowgroup.h"
+#include "gtkpopover.h"
 #include "gtkentry.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
@@ -526,6 +525,7 @@ gtk_entry_completion_constructed (GObject *object)
                     G_CALLBACK (gtk_entry_completion_list_activated),
                     completion);
 
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->tree_view), FALSE);
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view), TRUE);
   gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW (priv->tree_view), TRUE);
@@ -561,6 +561,7 @@ gtk_entry_completion_constructed (GObject *object)
   g_signal_connect (priv->action_view, "row-activated",
                     G_CALLBACK (gtk_entry_completion_action_activated),
                     completion);
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->action_view), FALSE);
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->action_view), FALSE);
   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->action_view), TRUE);
   gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW (priv->action_view), TRUE);
@@ -578,9 +579,8 @@ gtk_entry_completion_constructed (GObject *object)
                                               NULL);
 
   /* pack it all */
-  priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
-  gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
-  gtk_window_set_type_hint (GTK_WINDOW(priv->popup_window), GDK_SURFACE_TYPE_HINT_COMBO);
+  priv->popup_window = gtk_popover_new (NULL);
+  gtk_popover_set_position (GTK_POPOVER (priv->popup_window), GTK_POS_BOTTOM);
 
   controller = gtk_event_controller_key_new ();
   g_signal_connect (controller, "key-pressed",
@@ -762,38 +762,12 @@ gtk_entry_completion_dispose (GObject *object)
   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
   GtkEntryCompletionPrivate *priv = completion->priv;
 
-  if (priv->tree_view)
-    {
-      gtk_widget_destroy (priv->tree_view);
-      priv->tree_view = NULL;
-    }
-
   if (priv->entry)
     gtk_entry_set_completion (GTK_ENTRY (priv->entry), NULL);
 
-  if (priv->actions)
-    {
-      g_object_unref (priv->actions);
-      priv->actions = NULL;
-    }
-
-  if (priv->action_view)
-    {
-      g_object_unref (priv->action_view);
-      priv->action_view = NULL;
-    }
-
-  if (priv->popup_window)
-    {
-      gtk_widget_destroy (priv->popup_window);
-      priv->popup_window = NULL;
-    }
-
-  if (priv->cell_area)
-    {
-      g_object_unref (priv->cell_area);
-      priv->cell_area = NULL;
-    }
+  g_clear_object (&priv->actions);
+  g_clear_object (&priv->action_view);
+  g_clear_object (&priv->cell_area);
 
   G_OBJECT_CLASS (gtk_entry_completion_parent_class)->dispose (object);
 }
@@ -1461,39 +1435,11 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
                                     NULL, FALSE, 0.0, 0.0);
       gtk_tree_path_free (path);
     }
-
-  if (gtk_window_get_transient_for (GTK_WINDOW (completion->priv->popup_window)))
-    {
-      gdk_surface_move_to_rect (_gtk_widget_get_surface (completion->priv->popup_window),
-                                &allocation,
-                                GDK_GRAVITY_SOUTH,
-                                GDK_GRAVITY_NORTH,
-                                GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X,
-                                0, 0);
-      gtk_widget_show (completion->priv->popup_window);
-   }
-}
-
-static void
-prepare_popup_func (GdkSeat   *seat,
-                    GdkSurface *surface,
-                    gpointer   user_data)
-{
-  GtkEntryCompletion *completion = user_data;
-
-  /* prevent the first row being focused */
-  gtk_widget_grab_focus (completion->priv->tree_view);
-
-  gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
-  gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
-
-  gtk_widget_show (completion->priv->popup_window);
 }
 
 static void
 gtk_entry_completion_popup (GtkEntryCompletion *completion)
 {
-  GtkWidget *toplevel;
   GtkText *text = gtk_entry_get_text_widget (GTK_ENTRY (completion->priv->entry));
 
   if (gtk_widget_get_mapped (completion->priv->popup_window))
@@ -1505,40 +1451,14 @@ gtk_entry_completion_popup (GtkEntryCompletion *completion)
   if (!gtk_widget_has_focus (GTK_WIDGET (text)))
     return;
 
-  if (completion->priv->has_grab)
-    return;
-
-  gtk_widget_show (completion->priv->vbox);
-
   /* default on no match */
   completion->priv->current_selected = -1;
 
-  toplevel = gtk_widget_get_toplevel (completion->priv->entry);
-  if (GTK_IS_WINDOW (toplevel))
-    {
-      gtk_window_set_transient_for (GTK_WINDOW (completion->priv->popup_window),
-                                    GTK_WINDOW (toplevel));
-      gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-                                   GTK_WINDOW (completion->priv->popup_window));
-    }
-
-  gtk_window_set_display (GTK_WINDOW (completion->priv->popup_window),
-                          gtk_widget_get_display (completion->priv->entry));
   gtk_widget_realize (completion->priv->popup_window);
 
   _gtk_entry_completion_resize_popup (completion);
 
-  if (completion->priv->device)
-    {
-      gtk_grab_add (completion->priv->popup_window);
-      gdk_seat_grab (gdk_device_get_seat (completion->priv->device),
-                     gtk_widget_get_surface (completion->priv->popup_window),
-                     GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH,
-                     TRUE, NULL, NULL,
-                     prepare_popup_func, completion);
-
-      completion->priv->has_grab = TRUE;
-    }
+  gtk_popover_popup (GTK_POPOVER (completion->priv->popup_window));
 }
 
 void
@@ -1547,14 +1467,7 @@ _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
   if (!gtk_widget_get_mapped (completion->priv->popup_window))
     return;
 
-  if (completion->priv->has_grab)
-    {
-      gdk_seat_ungrab (gdk_device_get_seat (completion->priv->device));
-      gtk_grab_remove (completion->priv->popup_window);
-      completion->priv->has_grab = FALSE;
-    }
-
-  gtk_widget_hide (completion->priv->popup_window);
+  gtk_popover_popdown (GTK_POPOVER (completion->priv->popup_window));
 }
 
 static gboolean
@@ -2036,8 +1949,7 @@ gtk_entry_completion_timeout (gpointer data)
     }
   else if (gtk_widget_get_visible (completion->priv->popup_window))
     _gtk_entry_completion_popdown (completion);
-
-  return FALSE;
+  return G_SOURCE_REMOVE;
 }
 
 static inline gboolean
@@ -2428,6 +2340,15 @@ accept_completion_callback (GtkEntryCompletion *completion)
   return FALSE;
 }
 
+static gboolean
+text_focus_out (GtkEntryCompletion *completion)
+{
+  if (gtk_widget_get_mapped (completion->priv->popup_window))
+    return FALSE;
+
+  return accept_completion_callback (completion);
+}
+
 static void
 completion_insert_text_callback (GtkText            *entry,
                                  const gchar        *text,
@@ -2461,7 +2382,7 @@ connect_completion_signals (GtkEntryCompletion *completion)
   controller = priv->entry_key_controller = gtk_event_controller_key_new ();
   g_signal_connect (controller, "key-pressed",
                     G_CALLBACK (gtk_entry_completion_key_pressed), completion);
-  g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (accept_completion_callback), completion);
+  g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (text_focus_out), completion);
   gtk_widget_add_controller (GTK_WIDGET (text), controller);
 
   completion->priv->changed_id =
@@ -2548,10 +2469,8 @@ _gtk_entry_completion_disconnect (GtkEntryCompletion *completion)
 
   unset_accessible_relation (completion->priv->popup_window,
                              completion->priv->entry);
-  gtk_window_set_attached_to (GTK_WINDOW (completion->priv->popup_window),
-                              NULL);
-
-  gtk_window_set_transient_for (GTK_WINDOW (completion->priv->popup_window), NULL);
+  gtk_popover_set_relative_to (GTK_POPOVER (completion->priv->popup_window),
+                               NULL);
 
   completion->priv->entry = NULL;
 }
@@ -2564,7 +2483,7 @@ _gtk_entry_completion_connect (GtkEntryCompletion *completion,
 
   set_accessible_relation (completion->priv->popup_window,
                            completion->priv->entry);
-  gtk_window_set_attached_to (GTK_WINDOW (completion->priv->popup_window),
+  gtk_popover_set_relative_to (GTK_POPOVER (completion->priv->popup_window),
                               completion->priv->entry);
 
   connect_completion_signals (completion);